<script lang="ts" setup>
import { onMounted, onUnmounted, ref, reactive, nextTick } from 'vue'
import type { FormRules, FormInstance, ScrollbarInstance } from 'element-plus'
import type { IFieldProps } from './interface'

// Define types for better type safety
type RelationType = 'and' | 'or'
type OperatorValue =
  | 'eq'
  | 'ne'
  | 'gt'
  | 'lt'
  | 'gte'
  | 'lte'
  | 'like'
  | 'noLike'
  | 'isNull'
  | 'isNotNull'

interface Operator {
  label: string
  value: OperatorValue
}

interface FilterField {
  field: string
  oper: string
  value?: unknown
}

interface SearchFilterData {
  relation: RelationType
  fields: FilterField[]
}

const emits = defineEmits<{
  (e: 'update:modelValue', value: SearchFilterData): void
  (e: 'change', value: SearchFilterData): void
}>()

interface ComponentProps {
  modelValue: SearchFilterData
  fields?: IFieldProps[]
}

// Props with defaults
const props = withDefaults(defineProps<ComponentProps>(), {
  fields: () => [],
  modelValue: () => ({
    relation: 'and',
    fields: [],
  }),
})
// const props = defineProps<{
//   modelValue: SearchFilterData;
//   fields: IFieldProps[];
// }>();

const formRef = ref<FormInstance>()
const buttonRef = ref<HTMLButtonElement>()
const innerRef = ref<HTMLDivElement>()
const scrollbarRef = ref<ScrollbarInstance>()
const visible = ref(false)
const max = ref(0)

const allOperators: Operator[] = [
  { label: '等于', value: 'eq' },
  { label: '不等于', value: 'ne' },
  { label: '大于', value: 'gt' },
  { label: '小于', value: 'lt' },
  { label: '大于等于', value: 'gte' },
  { label: '小于等于', value: 'lte' },
  { label: '包含', value: 'like' },
  { label: '不包含', value: 'noLike' },
  { label: '为空', value: 'isNull' },
  { label: '不为空', value: 'isNotNull' },
]

const fieldOperators: Record<string, OperatorValue[]> = {
  datetime: ['eq', 'gt', 'lt', 'isNull', 'isNotNull'],
  date: ['eq', 'gt', 'lt', 'isNull', 'isNotNull'],
  number: ['eq', 'gt', 'lt', 'isNull', 'isNotNull'],
}

const formRules = reactive<FormRules>({})

const searchFilterData = ref<SearchFilterData>({
  relation: 'and',
  fields: [],
})

const clearSearchFilterItem = (): void => {
  searchFilterData.value.fields = []
}

const addSearchFilterItem = async (): Promise<void> => {
  const formEl = formRef.value
  if (!formEl) return

  try {
    await formEl.validate()
    searchFilterData.value.fields.push({
      field: '',
      oper: '',
      value: undefined,
    })

    await nextTick(() => {
      if (scrollbarRef.value && innerRef.value) {
        scrollbarRef.value.setScrollTop(innerRef.value.clientHeight)
      }
    })
  } catch (error) {
    console.error('Validation error:', error)
  }
}

const removeSearchFilterItem = (index: number): void => {
  searchFilterData.value.fields.splice(index, 1)
}

const handleVisible = async (): Promise<void> => {
  if (!visible.value) return

  const formEl = formRef.value
  if (!formEl) return

  // Auto close and clear if no valid selection
  if (searchFilterData.value.fields.length === 1 && !searchFilterData.value.fields[0].field) {
    visible.value = false
    searchFilterData.value.fields = []
    return
  }

  try {
    await formEl.validate()
    visible.value = false
  } catch (error) {
    console.error('Validation error:', error)
    ElMessage({
      message: '请设置合法的过滤条件',
      type: 'warning',
      grouping: true,
    })
  }
}

const getSearchFilterItem = (): void => {
  emits('update:modelValue', searchFilterData.value)
  emits('change', searchFilterData.value)
}

const getOperOptions = (field: string): Operator[] => {
  if (!field) return []

  const fieldItem = props.fields.find((item) => item.prop === field)
  if (!fieldItem?.type || !fieldOperators[fieldItem.type]) {
    return allOperators
  }

  return allOperators.filter(
    (o) => fieldItem.type && fieldOperators[fieldItem.type].includes(o.value),
  )
}

const getFieldConfig = (field: string): IFieldProps | undefined => {
  return props.fields.find((item) => item.prop === field)
}

const handleDocumentClick = (): void => {
  handleVisible()
}

onMounted(() => {
  document.getElementById('app')?.addEventListener('click', handleDocumentClick)
  if (innerRef.value) {
    max.value = innerRef.value.clientHeight - 380
  }
})

onUnmounted(() => {
  document.getElementById('app')?.removeEventListener('click', handleDocumentClick)
})
</script>

<template>
  <el-tooltip class="box-item" effect="dark" content="高级搜索" placement="top">
    <el-button
      class="search-filter-btn"
      ref="buttonRef"
      type="primary"
      @click.stop="visible = true"
      plain
    >
      <el-badge
        is-dot
        :value="searchFilterData.fields.length"
        :hidden="!searchFilterData.fields.length"
      >
        <el-icon>
          <Filter />
        </el-icon>
      </el-badge>
    </el-button>
  </el-tooltip>
  <el-popover
    :visible="visible"
    placement="bottom-end"
    :width="560"
    trigger="click"
    @hide="getSearchFilterItem"
    :virtual-ref="buttonRef"
    virtual-triggering
  >
    <div @click.prevent.stop>
      <el-form :rules="formRules" ref="formRef" :model="searchFilterData" label-width="0">
        <div class="pb-2">
          <div class="flex justify-between items-center">
            <div>
              <span>设置筛选条件</span>
            </div>
            <div>
              <el-form-item labelWidth="0" prop="relation" style="margin: 0">
                <el-select
                  v-model="searchFilterData.relation"
                  placeholder="请选择"
                  style="width: 140px"
                  :popperAppendToBody="false"
                  size="small"
                >
                  <el-option label="符合以下所有条件" value="and" />
                  <el-option label="符合以下任一条件" value="or" />
                </el-select>
              </el-form-item>
            </div>
          </div>
        </div>
        <div style="max-height: 220px; margin-right: -12px" v-if="searchFilterData.fields.length">
          <el-scrollbar
            ref="scrollbarRef"
            :height="searchFilterData.fields.length > 5 ? '220px' : 'auto'"
            always
          >
            <div style="padding-right: 12px" ref="innerRef">
              <div class="flex pb-2" v-for="(i, index) in searchFilterData.fields" :key="index">
                <div class="flex-1">
                  <el-row :gutter="10">
                    <el-col :span="8">
                      <el-form-item
                        :prop="['fields', index.toString(), 'field']"
                        style="margin: 0"
                        required
                        inline-message
                        :show-message="false"
                      >
                        <el-select
                          v-model="i.field"
                          placeholder="请选择"
                          :popperAppendToBody="false"
                        >
                          <el-option
                            v-for="o in fields"
                            :key="o.prop"
                            :label="o.label"
                            :value="o.prop"
                          />
                        </el-select>
                      </el-form-item>
                    </el-col>
                    <el-col :span="8">
                      <el-form-item
                        :prop="['fields', index.toString(), 'oper']"
                        style="margin: 0"
                        required
                        inline-message
                        :show-message="false"
                      >
                        <el-select
                          v-model="i.oper"
                          placeholder="请选择"
                          :popperAppendToBody="false"
                        >
                          <el-option
                            v-for="o in getOperOptions(i.field)"
                            :key="o.value"
                            :label="o.label"
                            :value="o.value"
                          />
                        </el-select>
                      </el-form-item>
                    </el-col>
                    <el-col :span="8">
                      <template v-if="i.oper !== 'isNull' && i.oper !== 'isNotNull'">
                        <el-form-item
                          :prop="['fields', index.toString(), 'value']"
                          style="margin: 0"
                          required
                          inline-message
                          :show-message="false"
                        >
                          <el-date-picker
                            style="width: 100%"
                            type="datetime"
                            v-if="getFieldConfig(i.field)?.type === 'datetime'"
                            v-model="i.value"
                            placeholder="请输入"
                          />

                          <el-input-number
                            style="width: 100%"
                            v-else-if="getFieldConfig(i.field)?.type === 'number'"
                            v-model="i.value"
                            controls-position="right"
                          />

                          <el-input
                            style="width: 100%"
                            v-else
                            v-model="i.value"
                            placeholder="请输入"
                          />
                        </el-form-item>
                      </template>
                    </el-col>
                  </el-row>
                </div>
                <div style="width: 24px; margin-left: 10px">
                  <el-button text icon="Close" circle @click="removeSearchFilterItem(index)" />
                </div>
              </div>
            </div>
          </el-scrollbar>
        </div>
        <div class="flex justify-center" v-else>
          <el-empty description="点击下方按钮添加过滤条件" :image-size="80" />
        </div>
        <div class="flex pt-2">
          <el-button type="primary" @click="addSearchFilterItem" size="small">添加条件</el-button>
          <el-button
            v-if="searchFilterData.fields.length"
            link
            @click="clearSearchFilterItem"
            size="small"
            >清空条件
          </el-button>
        </div>
      </el-form>
    </div>
  </el-popover>
</template>
